import guid from './guid.ts'
let timer,dateTime = new Date().getTime(),callback,sse
function interval() {
	clearInterval(timer)
	timer= setInterval(()=>{
		let timeDiff= new Date().getTime() - dateTime
		if(timeDiff>15000){
			removeSSEListeners()
			dateTime = new Date().getTime()
			console.log('15秒后手动连接');
			connect(callback)
		}
	},1000)
}
/**
 * 原生的 new EventSource()的sse连接写法
 *@returns callback 回调消息
 */
function connect(callbackFn) {
	callback = callbackFn
	let token = JSON.parse(localStorage.getItem('token')).ACCESS_TOKEN
	let uuid = guid(32)
	const url = `/api/common/sse/connect?clientId=pc_${uuid}&YX-Tenant-Token=${token}`
	sse = new EventSource(url);
	sse.addEventListener("open", openFn)
	// 收到角标消息
	sse.addEventListener("subscript", subscriptFn)
	// 收到心跳消息
	sse.addEventListener("heartbeat", heartbeatFn)
	sse.addEventListener('error', errorFn)
}

function openFn (e){
	console.log('开启连接');
	// 建立心跳检查
	interval()
}
function subscriptFn (data){
	console.log('收到消息');
	callback && callback('subscript', data)
}
function heartbeatFn (data){
	console.log('收到心跳消息');
	dateTime = new Date().getTime()
	callback && callback('heartbeat', data)
}
function errorFn (err){
	// 报错
	console.log('err');
	if (sse.readyState === EventSource.CLOSED) {
		console.log("服务端主动断开连接‌:");
	}
}

/**
 * see连接优先使用原生的 new EventSource(),如果业务需求强制使用post请求则可以使用这个方法
 * @param {*} req 请求参数 
 */
function connectSSE(req) {
	// 开启角标任务
	fetch('/api/web/org/role/sse/stream', {
		method: 'POST',
		body: JSON.stringify(req),
		headers: {
			'YX-Tenant-Token': token,
			'Content-Type': 'application/json'
		},
	}).then(async response => {
		// 获取响应体的 ReadableStream 读取器
		const reader = response.body.getReader();
		// 文本解码器，用于将二进制数据转换为字符串
		const decoder = new TextDecoder();
		// 缓存区：处理跨 chunk 的不完整数据
		let buffer = '';
		// 无限循环：持续读取数据流
		while (true) {
			// 读取下一个 chunk 数据（包含 done 和 value）
			const { done, value } = await reader.read();
			// 流结束时退出循环
			if (done) break;
			// 将当前 chunk 解码并追加到缓存区（stream: true 表示可能还有后续数据）
			buffer += decoder.decode(value, {
				stream: true
			});
			// 循环处理缓存区中的完整事件（以 \n\n 分隔）
			let eventEndIndex;
			while ((eventEndIndex = buffer.indexOf('\n\n')) >= 0) {
				// 提取一个完整事件的数据（从缓存区开头到分隔符前）
				const eventData = buffer.slice(0, eventEndIndex);
				// 更新缓存区，移除已处理的事件数据
				buffer = buffer.slice(eventEndIndex + 2);// +2 跳过两个换行符
				// 解析单个事件内容
				parseSSEEvent(eventData);
			}
		}
	})
}
// 函数：解析单个 SSE 事件
function parseSSEEvent(rawEvent) {
	const event = {
		type: 'message', // 默认事件类型
		data: '',
		id: null,
		retry: null
	};

	// 将原始事件按行分割，遍历处理每行内容
	rawEvent.split('\n').forEach(line => {
		// 处理事件类型（例如 event: customEvent）
		if (line.startsWith('event:')) {
			event.type = line.replace('event:', '').trim();
		}
		// 处理数据行（允许多行 data，用换行符连接）
		else if (line.startsWith('data:')) {
			event.data += line.replace('data:', '').trim() + '\n';
		}
		// 处理事件 ID（用于服务端追踪）
		else if (line.startsWith('id:')) {
			event.id = line.replace('id:', '').trim();
		}
		// 处理重连时间（调整客户端重连间隔）
		else if (line.startsWith('retry:')) {
			event.retry = parseInt(line.replace('retry:', '').trim(), 10);
		}
	});
	// 清理 data 末尾的换行符（避免 JSON 解析错误）
	event.data = event.data.trimEnd();

	// 如果 data 存在内容，进行处理
	if (event.data) {
		try {
			// 解析 JSON 格式的 data
			const parsedData = JSON.parse(event.data);
			// console.log(`[${event.type}]`, parsedData);
			// 根据事件类型分发到不同处理器
			if (event.type === 'customEvent') {
				handleCustomEvent(parsedData); // 处理自定义事件
			} else if (event.type === 'message') {
				handleDefaultEvent(parsedData); // 处理默认事件
			}
		} catch (e) {
			console.error('JSON 解析失败:', e);
		}
	}
}
// 示例事件处理器
function handleCustomEvent(data) {
	console.log('收到自定义事件:');
}

function handleDefaultEvent(data) {
	console.log('收到默认事件:');
}
// 移除监听
function removeSSEListeners() {
	if(!sse){
		return
	}
	console.log('移除监听')
    // 移除所有事件监听器
    sse.removeEventListener('open',openFn);
    sse.removeEventListener('subscript',subscriptFn);
    sse.removeEventListener('heartbeat',heartbeatFn);
    sse.removeEventListener('error',errorFn);
    
    // 关闭连接
    sse.close();
}
export default {
	connect,
	removeSSEListeners
}